(SST) ShlWAPI.pas Version 1.08

Developer Reference
(SST)ShlWAPI PathAppend Function
Merges two path strings.
Scope
Global (i.e. this function can be called/accessed from code in any unit that includes/uses (SST)ShlWAPI.pas).
Syntax
function PathAppend(pszPath : LPSTR; pszMore : LPCSTR) : BOOL;
Parameters
pszPath [in/out] The address of (or pointer to) the NULL-terminated, ANSI or Unicode character buffer, that on input contains the first path to merge with the path specified in the second parameter. If the function succedds it returns the merged path in this buffer. The buffer must therefore be large enough to accomodate the merged path string and a terminating single or double byte null-character (depending on whether the ANSI or Unicode version of the function is called).
pszMore [in] Pointer to the second null-terminated path string to merge with that specified in parameter pszPath.
Return Values
If the function succeeds it returns TRUE (=1), FALSE (=0) if not.
Remarks
Unless an obviously invalid parameter is specified, such as a null-pointer to either parameter, the function appears to always return TRUE (=1), even if the subsequently merged path is erroneous (see examples 10 & 11, below). Furthermore, neither an empty I/O buffer (i.e. the buffer specified in pszPath), nor an empty string as the second parameter (i.e. pszMore) are apparently considered invalid parameters (see examples 16 & 18, below).
If both paths are fully qualified paths from the root on down, the function returns TRUE and replaces the initial path in the buffer with the path specified in the second parameter (see examples 1, 2, 12, 13, and 14 below).
The function only performs as documented and exemplified in the help that accompanied various MS SDKs, if the path specified in the second parameter (pszMore) is a partial, non-relative path (see examples 3 & 4, below), otherwise the paths are merged and not concatenated (i.e. the function does not merely "append" the path specified in the second parameter).
If the path specified in the pszMore parameter is a relative path, it is merged into the path with which the I/O buffer pszPath was initialized. That is, the second (relative) path is assumed to be relative to the path specified in pszPath and replaces some of its components, while other parts (if any) that extend "below" it are appended (see examples 5, 6, 7, 8, 9, & 19 below). This is presumably the true/intended purpose of the function and as such it has to be considered pretty useful. A more appropriate name for the function would therefore be "PathMergeRelPath".
The function only supports paths delimited by DOS/Windows path delimiters (i.e. backslashes). If either parameter includes one or more slashes instead of backslashes, the returned path is likely to be syntactically incorrect (see example 11, below) and the function will return TRUE in spite of the error.
The function does not require that the first parameter be terminated by a backslash. Nor, does the second parameter have to have a leading backslash. If a backslash is required to separate the concatenated components, it is added by the function.
It does not appear to be necessary to enclose paths that have blanks/spaces in the names of their components in quotation marks (see example 6, below).
The function returns TRUE (=1) even if the size of the buffer is not large enough to (fully) accomodate the merged path. In these cases, the function simply truncates the merged path so that it, and the terminating null-character, will fit into the available buffer (at least under Windows Vista with Service Pack 1 and IE 8) (see last example, below).
The function does not verify the existence of either, input path, nor that of the returned, merged or concatenated path.
Example
PROCEDURE TForm4.TestShlWAPIPathAppend(Sender : TObject); VAR examplenum : INTEGER; VAR combinedpathsbuf : ARRAY[0.. MAX_PATH] OF CHAR; VAR tooshortpathsbuf : ARRAY[0.. 32] OF CHAR; VAR pathstrlen : DWORD; VAR pathtoappend : STRING; VAR apiretval : BOOL; VAR newinfoline : STRING; BEGIN examplenum := 0; FillChar(combinedpathsbuf, Length(combinedpathsbuf), #0); FillChar(tooshortpathsbuf, Length(tooshortpathsbuf), #0); pathstrlen := 0; pathtoappend := ''; apiretval := FALSE; newinfoline := ''; //Two fully qualified paths Inc(examplenum); combinedpathsbuf := 'C:\Windows\System32\Drivers'; pathtoappend := 'C:\Hello\World'; newinfoline := '(' + IntToStr(examplenum) + ') PathAppend called with ' + combinedpathsbuf + ' and ' + pathtoappend; Memo1.Lines.Add(newinfoline); newinfoline := 'returned : '; //Memo1.Lines.Add(newinfoline); apiretval := PathAppend(combinedpathsbuf, PChar(pathtoappend)); IF apiretval THEN newinfoline := newinfoline + 'TRUE ' + combinedpathsbuf ELSE newinfoline := newinfoline + 'FALSE ' + combinedpathsbuf; Memo1.Lines.Add(newinfoline); Memo1.Lines.Add(''); Inc(examplenum); combinedpathsbuf := 'C:\Hello\World'; pathtoappend := 'C:\Windows\System32\Drivers'; newinfoline := '(' + IntToStr(examplenum) + ') PathAppend called with '+ combinedpathsbuf + ' and ' + pathtoappend; Memo1.Lines.Add(newinfoline); newinfoline := 'returned : '; //Memo1.Lines.Add(newinfoline); apiretval := PathAppend(combinedpathsbuf, PChar(pathtoappend)); IF apiretval THEN newinfoline := newinfoline + 'TRUE ' + combinedpathsbuf ELSE newinfoline := newinfoline + 'FALSE ' + combinedpathsbuf; Memo1.Lines.Add(newinfoline); Memo1.Lines.Add(''); //A fully qualified path and a partial/relative path Inc(examplenum); combinedpathsbuf := 'C:\Windows\System32\Drivers'; pathtoappend := 'Hello\World'; newinfoline := '(' + IntToStr(examplenum) + ') PathAppend called with ' + combinedpathsbuf + ' and ' + pathtoappend; Memo1.Lines.Add(newinfoline); newinfoline := 'returned : '; //Memo1.Lines.Add(newinfoline); apiretval := PathAppend(combinedpathsbuf, PChar(pathtoappend)); IF apiretval THEN newinfoline := newinfoline + 'TRUE ' + combinedpathsbuf ELSE newinfoline := newinfoline + 'FALSE ' + combinedpathsbuf; Memo1.Lines.Add(newinfoline); Memo1.Lines.Add(''); Inc(examplenum); combinedpathsbuf := 'C:\Windows\System32\Drivers\'; pathtoappend := 'Hello\World\DummyFileName.drv'; newinfoline := '(' + IntToStr(examplenum) + ') PathAppend called with ' + combinedpathsbuf + ' and ' + pathtoappend; Memo1.Lines.Add(newinfoline); newinfoline := 'returned : '; //Memo1.Lines.Add(newinfoline); apiretval := PathAppend(combinedpathsbuf, PChar(pathtoappend)); IF apiretval THEN newinfoline := newinfoline + 'TRUE ' + combinedpathsbuf ELSE newinfoline := newinfoline + 'FALSE ' + combinedpathsbuf; Memo1.Lines.Add(newinfoline); Memo1.Lines.Add(''); Inc(examplenum); combinedpathsbuf := '..\Windows\System32\Drivers'; pathtoappend := '..\Hello\World'; newinfoline := '(' + IntToStr(examplenum) + ') PathAppend called with ' + combinedpathsbuf + ' and ' + pathtoappend; Memo1.Lines.Add(newinfoline); newinfoline := 'returned : '; //Memo1.Lines.Add(newinfoline); apiretval := PathAppend(combinedpathsbuf, PChar(pathtoappend)); IF apiretval THEN newinfoline := newinfoline + 'TRUE ' + combinedpathsbuf ELSE newinfoline := newinfoline + 'FALSE ' + combinedpathsbuf; Memo1.Lines.Add(newinfoline); Memo1.Lines.Add(''); Inc(examplenum); combinedpathsbuf := 'C:\Windows\System32\Drivers'; pathtoappend := '..\Hello\Danish Viking\Kings With Blue Teeth '; newinfoline := '(' + IntToStr(examplenum) + ') PathAppend called with ' + combinedpathsbuf + ' and ' + pathtoappend; Memo1.Lines.Add(newinfoline); newinfoline := 'returned : '; apiretval := PathAppend(combinedpathsbuf, PChar(pathtoappend)); IF apiretval THEN newinfoline := newinfoline + 'TRUE ' + combinedpathsbuf ELSE newinfoline := newinfoline + 'FALSE ' + combinedpathsbuf; Memo1.Lines.Add(newinfoline); Memo1.Lines.Add(''); Inc(examplenum); combinedpathsbuf := '..\Windows\System32\Drivers\Blue Teeth\Bluetooth.drv.sys'; pathtoappend := '..\..\Hello\Driver World'; newinfoline := '(' + IntToStr(examplenum) + ') PathAppend called with ' + combinedpathsbuf + ' and ' + pathtoappend; Memo1.Lines.Add(newinfoline); newinfoline := 'returned : '; apiretval := PathAppend(combinedpathsbuf, PChar(pathtoappend)); IF apiretval THEN newinfoline := newinfoline + 'TRUE ' + combinedpathsbuf ELSE newinfoline := newinfoline + 'FALSE ' + combinedpathsbuf; Memo1.Lines.Add(newinfoline); Memo1.Lines.Add(''); Inc(examplenum); combinedpathsbuf := '..\Windows\System32\Drivers\Bluetooth\'; pathtoappend := '..\..\Hello\World\Bluto~1.inf'; newinfoline := '(' + IntToStr(examplenum) + ') PathAppend called with ' + combinedpathsbuf + ' and ' + pathtoappend; Memo1.Lines.Add(newinfoline); newinfoline := 'returned : '; apiretval := PathAppend(combinedpathsbuf, PChar(pathtoappend)); IF apiretval THEN newinfoline := newinfoline + 'TRUE ' + combinedpathsbuf ELSE newinfoline := newinfoline + 'FALSE ' + combinedpathsbuf; Memo1.Lines.Add(newinfoline); Memo1.Lines.Add(''); Inc(examplenum); combinedpathsbuf := '..\Windows\System32\Drivers\Bluetooth\Repository\Bluetooth.sys'; pathtoappend := '..\..\Hello\World\Bluto~1.inf'; newinfoline := '(' + IntToStr(examplenum) + ') PathAppend called with ' + combinedpathsbuf + ' and ' + pathtoappend; Memo1.Lines.Add(newinfoline); newinfoline := 'returned : '; apiretval := PathAppend(combinedpathsbuf, PChar(pathtoappend)); IF apiretval THEN newinfoline := newinfoline + 'TRUE ' + combinedpathsbuf ELSE newinfoline := newinfoline + 'FALSE ' + combinedpathsbuf; Memo1.Lines.Add(newinfoline); Memo1.Lines.Add(''); Inc(examplenum); combinedpathsbuf := '..\Windows\System32\Drivers\Cache\en-US'; pathtoappend := '../../Hello/World'; newinfoline := '(' + IntToStr(examplenum) + ') PathAppend called with ' + combinedpathsbuf + ' and ' + pathtoappend; Memo1.Lines.Add(newinfoline); newinfoline := 'returned : '; apiretval := PathAppend(combinedpathsbuf, PChar(pathtoappend)); IF apiretval THEN newinfoline := newinfoline + 'TRUE ' + combinedpathsbuf ELSE newinfoline := newinfoline + 'FALSE ' + combinedpathsbuf; Memo1.Lines.Add(newinfoline); Memo1.Lines.Add(''); Inc(examplenum); combinedpathsbuf := '../Windows/System32/Drivers/Cache/en-US'; pathtoappend := '../../Hello/World'; newinfoline := '(' + IntToStr(examplenum) + ') PathAppend called with ' + combinedpathsbuf + ' and ' + pathtoappend; Memo1.Lines.Add(newinfoline); newinfoline := 'returned : '; apiretval := PathAppend(combinedpathsbuf, PChar(pathtoappend)); IF apiretval THEN newinfoline := newinfoline + 'TRUE ' + combinedpathsbuf ELSE newinfoline := newinfoline + 'FALSE ' + combinedpathsbuf; Memo1.Lines.Add(newinfoline); Memo1.Lines.Add(''); //Two fully qualified UNC server/share paths Inc(examplenum); combinedpathsbuf := '\\UNCServer1\Share1\Windows\System32\Drivers\'; pathtoappend := '\\UNCServer2\Share2\Hello\World\'; newinfoline := '(' + IntToStr(examplenum) + ') PathAppend called with ' + combinedpathsbuf + ' and ' + pathtoappend; Memo1.Lines.Add(newinfoline); newinfoline := 'returned : '; apiretval := PathAppend(combinedpathsbuf, PChar(pathtoappend)); IF apiretval THEN newinfoline := newinfoline + 'TRUE ' + combinedpathsbuf ELSE newinfoline := newinfoline + 'FALSE ' + combinedpathsbuf; Memo1.Lines.Add(newinfoline); Memo1.Lines.Add(''); Inc(examplenum); combinedpathsbuf := '\\UNCServer1\Share1\Windows\System32\Drivers\' + 'Bluethooth\Bluetooth.sys'; pathtoappend := '\\UNCServer2\Share2\Hello\World\BluethoothDrivers.inf'; newinfoline := '(' + IntToStr(examplenum) + ') PathAppend called with ' + combinedpathsbuf + ' and ' + pathtoappend; Memo1.Lines.Add(newinfoline); newinfoline := 'returned : '; apiretval := PathAppend(combinedpathsbuf, PChar(pathtoappend)); IF apiretval THEN newinfoline := newinfoline + 'TRUE ' + combinedpathsbuf ELSE newinfoline := newinfoline + 'FALSE ' + combinedpathsbuf; Memo1.Lines.Add(newinfoline); Memo1.Lines.Add(''); //Two fully qualified "file: etc. paths" Inc(examplenum); combinedpathsbuf := 'file:///S:/Projects/SST/Website/en/products/' + 'development%20libraries/delphi/shlwapi/' + 'support/devref/functions/DllGetVersion.htm'; pathtoappend := '..\Hello\World\BluethoothDrivers.inf'; newinfoline := '(' + IntToStr(examplenum) + ') PathAppend called with ' + combinedpathsbuf + ' and ' + pathtoappend; Memo1.Lines.Add(newinfoline); newinfoline := 'returned : '; apiretval := PathAppend(combinedpathsbuf, PChar(pathtoappend)); IF apiretval THEN newinfoline := newinfoline + 'TRUE ' + combinedpathsbuf ELSE newinfoline := newinfoline + 'FALSE ' + combinedpathsbuf; Memo1.Lines.Add(newinfoline); Memo1.Lines.Add(''); Inc(examplenum); combinedpathsbuf := 'file:\\\S:\Projects\SST\Website\en\products\' + 'development%20libraries\delphi\shlwapi\support\' + 'devref\functions\DllGetVersion.htm'; pathtoappend := '..\Hello\World\DllVersion.exe'; newinfoline := '(' + IntToStr(examplenum) + ') PathAppend called with ' + combinedpathsbuf + ' and ' + pathtoappend; Memo1.Lines.Add(newinfoline); newinfoline := 'returned : '; apiretval := PathAppend(combinedpathsbuf, PChar(pathtoappend)); IF apiretval THEN newinfoline := newinfoline + 'TRUE ' + combinedpathsbuf ELSE newinfoline := newinfoline + 'FALSE ' + combinedpathsbuf; Memo1.Lines.Add(newinfoline); Memo1.Lines.Add(''); //Try to force some errors by passing in invalid params Inc(examplenum); combinedpathsbuf := 'C:\Windows\System32\Drivers\Cache\en-US\acpi.sys.mui'; pathtoappend := ''; //Empty string newinfoline := '(' + IntToStr(examplenum) + ') PathAppend called with ' + combinedpathsbuf + ' and an empty string as the second param'; Memo1.Lines.Add(newinfoline); newinfoline := 'returned : '; apiretval := PathAppend(combinedpathsbuf, PChar(pathtoappend)); IF apiretval THEN newinfoline := newinfoline + 'TRUE ' + combinedpathsbuf ELSE newinfoline := newinfoline + 'FALSE ' + combinedpathsbuf; Memo1.Lines.Add(newinfoline); Memo1.Lines.Add(''); Inc(examplenum); combinedpathsbuf := 'C:\Windows\System32\Drivers\Cache\en-US\' + 'battc.sys.mui'; pathtoappend := ''; //invalid (null) string newinfoline := '(' + IntToStr(examplenum) + ') PathAppend called with ' + combinedpathsbuf + ' and NIL pointer to second string'; Memo1.Lines.Add(newinfoline); newinfoline := 'returned : '; apiretval := PathAppend(combinedpathsbuf, NIL); IF apiretval THEN newinfoline := newinfoline + 'TRUE ' + combinedpathsbuf ELSE newinfoline := newinfoline + 'FALSE ' + combinedpathsbuf; Memo1.Lines.Add(newinfoline); Memo1.Lines.Add(''); Inc(examplenum); FillChar(combinedpathsbuf, Length(combinedpathsbuf), #0); pathtoappend := ''; //Empty string newinfoline := '(' + IntToStr(examplenum) + ') PathAppend called with ' + 'an empty buffer and string as the first and second param'; Memo1.Lines.Add(newinfoline); newinfoline := 'returned : '; apiretval := PathAppend(combinedpathsbuf, PChar(pathtoappend)); IF apiretval THEN newinfoline := newinfoline + 'TRUE ' + combinedpathsbuf ELSE newinfoline := newinfoline + 'FALSE ' + combinedpathsbuf; Memo1.Lines.Add(newinfoline); Memo1.Lines.Add(''); Inc(examplenum); combinedpathsbuf := 'C:\Windows\System32\Drivers'; pathtoappend := '..\..\..\..\..\Hello\World'; newinfoline := '(' + IntToStr(examplenum) + ') PathAppend called with ' + combinedpathsbuf + ' and ' + pathtoappend; Memo1.Lines.Add(newinfoline); newinfoline := 'returned : '; apiretval := PathAppend(combinedpathsbuf, PChar(pathtoappend)); IF apiretval THEN newinfoline := newinfoline + 'TRUE ' + combinedpathsbuf ELSE newinfoline := newinfoline + 'FALSE ' + combinedpathsbuf; Memo1.Lines.Add(newinfoline); Memo1.Lines.Add(''); Inc(examplenum); tooshortpathsbuf := 'C:\Windows\System32\Drivers'; pathtoappend := '..\Hello\World\New World\Dummy File Name.ext'; newinfoline := '(' + IntToStr(examplenum) + ') PathAppend called with ' + tooshortpathsbuf + ' and ' + pathtoappend; Memo1.Lines.Add(newinfoline); newinfoline := 'returned : '; apiretval := PathAppend(tooshortpathsbuf, PChar(pathtoappend)); IF apiretval THEN newinfoline := newinfoline + 'TRUE ' + tooshortpathsbuf ELSE newinfoline := newinfoline + 'FALSE ' + tooshortpathsbuf; Memo1.Lines.Add(newinfoline); Memo1.Lines.Add(''); Memo1.Lines.Add(''); END;
Under Windows Vista with Service Pack 1 (SP 1) and Internet Explorer 8 (IE 8), the above code produced the following results. Note, that in order to reduce the line lengths, line breaks were added manually to the output (i.e. some line breaks are not produced by the above code). As a result, in some cases a single, very long path may extend over several lines.
(1) PathAppend called with C:\Windows\System32\Drivers and C:\Hello\World returned : TRUE C:\Hello\World (2) PathAppend called with C:\Hello\World and C:\Windows\System32\Drivers returned : TRUE C:\Windows\System32\Drivers (3) PathAppend called with C:\Windows\System32\Drivers and Hello\World returned : TRUE C:\Windows\System32\Drivers\Hello\World (4) PathAppend called with C:\Windows\System32\Drivers\ and Hello\World\DummyFileName.drv returned : TRUE C:\Windows\System32\Drivers\Hello\World\DummyFileName.drv (5) PathAppend called with ..\Windows\System32\Drivers and ..\Hello\World returned : TRUE Windows\System32\Hello\World (6) PathAppend called with C:\Windows\System32\Drivers and ..\Hello\Danish Viking\Kings With Blue Teeth returned : TRUE C:\Windows\System32\Hello\Danish Viking\Kings With Blue Teeth (7) PathAppend called with ..\Windows\System32\Drivers\Blue Teeth\Bluetooth.drv.sys and ..\..\Hello\Driver World returned : TRUE Windows\System32\Drivers\Hello\Driver World (8) PathAppend called with ..\Windows\System32\Drivers\Bluetooth\ and ..\..\Hello\World\Bluto~1.inf returned : TRUE Windows\System32\Hello\World\Bluto~1.inf (9) PathAppend called with ..\Windows\System32\Drivers\Bluetooth\Repository\Bluetooth.sys and ..\..\Hello\World\Bluto~1.inf returned : TRUE Windows\System32\Drivers\Bluetooth\Hello\World\Bluto~1.inf (10) PathAppend called with ..\Windows\System32\Drivers\Cache\en-US and ../../Hello/World returned : TRUE Windows\System32\Drivers\Cache\en-US\../../Hello/World (11) PathAppend called with ../Windows/System32/Drivers/Cache/en-US and ../../Hello/World returned : TRUE ../Windows/System32/Drivers/Cache/en-US\../../Hello/World (12) PathAppend called with \\UNCServer1\Share1\Windows\System32\Drivers\ and \\UNCServer2\Share2\Hello\World\ returned : TRUE \\UNCServer2\Share2\Hello\World\ (13) PathAppend called with \\UNCServer1\Share1\Windows\System32\Drivers\Bluethooth\Bluetooth.sys and \\UNCServer2\Share2\Hello\World\BluethoothDrivers.inf returned : TRUE \\UNCServer2\Share2\Hello\World\BluethoothDrivers.inf (14) PathAppend called with file:///S:/Projects/SST/Website/en/products/development%20libraries/ delphi/shlwapi/support/devref/functions/DllGetVersion.htm and ..\Hello\World\BluethoothDrivers.inf returned : TRUE \Hello\World\BluethoothDrivers.inf (15) PathAppend called with file:\\\S:\Projects\SST\Website\en\products\development%20libraries\ delphi\shlwapi\support\devref\functions\DllGetVersion.htm and ..\Hello\World\DllVersion.exe returned : TRUE file:\\\S:\Projects\SST\Website\en\products\development%20libraries\delphi\ shlwapi\support\devref\functions\Hello\World\DllVersion.exe (16) PathAppend called with C:\Windows\System32\Drivers\Cache\en-US\acpi.sys.mui and an empty string as the second param returned : TRUE C:\Windows\System32\Drivers\Cache\en-US\acpi.sys.mui (17) PathAppend called with C:\Windows\System32\Drivers\Cache\en-US\battc.sys.mui and NIL pointer to second string returned : FALSE C:\Windows\System32\Drivers\Cache\en-US\battc.sys.mui (18) PathAppend called with an empty buffer and string as the first and second param returned : TRUE \ (19) PathAppend called with C:\Windows\System32\Drivers and ..\..\..\..\..\Hello\World returned : TRUE C:\Hello\World (20) PathAppend called with C:\Windows\System32\Drivers and ..\Hello\World\New World\Dummy File Name.ext returned : TRUE C:\Windows\System32\Hello\World\N
Requirements
Unit: Declared and imported in (SST)ShlWAPI.pas
Library: (SST)ShlWAPI.dcu/(SST)ShlWAPI.obj
Unicode: Implemented as ANSI (PathAppend and PathAppendA) and Unicode (PathAppendW) functions.
Min. ShlWAPI.dll version according to MS SDK doc.: 4.71
Min. ShlWAPI.dll version based on SST research: 4.71
Min. OS version(s) according to Microsoft SDK doc.: Windows 2000, Windows NT 4.0 with Internet Explorer 4.0, Windows 98, Windows 95 with Internet Explorer 4.0
Min. OS version(s) according to SST research.: Windows NT 4.0 with IE 4.0, Windows 95 with IE 4.0, Windows 98, Windows 2000 and later
See Also
PathCombine,
 
Windows APIs: PathCombine, PathAppend


Document/Contents version 1.00
Page/URI last updated on 07.12.2023
 
Copyright © Stoelzel Software Technologie (SST) 2010 - 2015
Suggestions and comments mail to:
webmaster@stoelzelsoftwaretech.com